package com.ymy.thinking.in.spring.bean.scope;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Bean 的作用域
 * <p>
 * 结论一：
 * Singleton Bean 无论是 依赖查找还是依赖注入，均为同一个对象。
 * Prototype Bean 无论是 依赖查找还是依赖注入，均为新创建的对象。
 * <p>
 * 结论二：
 * 如果依赖注入集合类型的对象，Singleton Bean 和 Prototype Bean 均会存在一个
 * <p>
 * 结论三：
 * 无论是 Singleton Bean 还是 Prototype Bean 均会执行初始化方法回调。
 * 但是，只有 Singleton Bean 会执行销毁方法回调。
 *
 * @author Ringo
 * @date 2022/2/5 19:39
 */
public class BeanScopeDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanScopeDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    if (bean instanceof User) {
                        System.out.println(beanName + "在初始化后回调");
                    }
                    return bean;
                }
            });
        });

        applicationContext.refresh();

        dependencyLookup(applicationContext, "singletonUser");
        dependencyLookup(applicationContext, "singletonUser");
        dependencyLookup(applicationContext, "prototypeUser");
        dependencyLookup(applicationContext, "prototypeUser");

        applicationContext.close();
    }


    public static void dependencyLookup(ApplicationContext applicationContext, String beanName) {
        User bean = applicationContext.getBean(beanName, User.class);
        System.out.println(bean);
    }

    @Bean
    public static User singletonUser() {
        return createUser();
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static User prototypeUser() {
        return createUser();
    }

    private static User createUser() {
        return new User();
    }


    private static class User implements BeanNameAware {

        private String id;

        private String name;

        private String beanName;

        @Override
        public void setBeanName(String name) {
            this.beanName = name;
        }

        // Singleton 和 Prototype 对象都会调用初始化方法
        @PostConstruct
        public void init() {
            System.out.println(beanName + " init...");
        }

        // 只有 Singleton 对象会调用初始化方法
        @PreDestroy
        public void destroy() {
            System.out.println(beanName + " Destroy...");
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


    }
}
